package com.cxy.contentcenter.service.content;

import com.alibaba.fastjson.JSON;
import com.cxy.contentcenter.dao.content.ShareMapper;
import com.cxy.contentcenter.dao.messaging.RocketmqTransactionLogMapper;
import com.cxy.contentcenter.dao.user.MidUserShareMapper;
import com.cxy.contentcenter.domain.dto.content.ShareAuditDTO;
import com.cxy.contentcenter.domain.dto.messaging.UserAddBonusMsgDTO;
import com.cxy.contentcenter.domain.dto.user.UserAddBonseDTO;
import com.cxy.contentcenter.domain.dto.user.UserDTO;
import com.cxy.contentcenter.domain.dto.content.ShareDTO;
import com.cxy.contentcenter.domain.entity.content.Share;
import com.cxy.contentcenter.domain.entity.messaging.RocketmqTransactionLog;
import com.cxy.contentcenter.domain.entity.user.MidUserShare;
import com.cxy.contentcenter.domain.enums.AuditStatusEnum;
import com.cxy.contentcenter.feignclient.UserCenterFeignClient;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.apache.rocketmq.spring.support.RocketMQHeaders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author: huayushu luming
 * @date: 2020-11-26 01:17
 * @desc:
 **/
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor =@__(@Autowired))
public class ShareService {
    private final ShareMapper shareMapper;
    private final UserCenterFeignClient userCenterFeignClient;
    private final RocketMQTemplate rocketMQTemplate;
    private final RocketmqTransactionLogMapper rocketmqTransactionLogMapper;
    private final Source source;
    private final MidUserShareMapper midUserShareMapper;
//    private final RestTemplate restTemplate;
//    private final DiscoveryClient discoveryClient;

    public ShareDTO findById(Integer id){
        //获取分享详情
        Share share = this.shareMapper.selectByPrimaryKey(id);
        //发布人ID
        Integer userId=share.getUserId();
        //用户中心所有实例的信息
//        List<ServiceInstance> instances = discoveryClient.getInstances("user-center");
        //务必了解stream
        //lambda表达式
        //functional 函数式编程
        //所有用户中心的实例算法
//        List<String> targetURLS = instances.stream()
//                .map(instance -> instance.getUri().toString() + "/users/{id}")
//                .collect(Collectors.toList());
//        int i=ThreadLocalRandom.current().nextInt(targetURLS.size());
//        String  targetURL=targetURLS.get(i);
//        log.info("请求目标地址：{}",targetURL);
        //怎么调用用户微服务的/users/{userId}??
        //ResponseEntity<String> forEntity = restTemplat.getForEntity("http://localhost:8084/users/{id}", String.class, userId);
        //UserDTO userDTO= restTemplate.getForObject("http://localhost:8084/users/{id}", UserDTO.class, userId);
//        UserDTO userDTO= restTemplate.getForObject("http://user-center/users/{id}", UserDTO.class, userId);
        UserDTO userDTO = this.userCenterFeignClient.findById(id);
        //消息装配
        ShareDTO shareDTO = new ShareDTO();
        BeanUtils.copyProperties(share,shareDTO);
        shareDTO.setWxNickName(userDTO.getWxNickname());
        return shareDTO;
    }

    public static void main(String[] args) {
        RestTemplate restTemplat=new RestTemplate();
        //用HTTP GET方法去请求，并且放回一个对象
        //String forObject = restTemplat.getForObject("http://localhost:8084/users/1", String.class);

        ResponseEntity<String> forEntity = restTemplat.getForEntity("http://localhost:8084/users/${id}", String.class, 1);
        System.out.println(forEntity.getBody());
        System.out.println(forEntity.getStatusCode());
        //System.out.println(forObject);
    }

    public Share auditById(Integer id, ShareAuditDTO auditDTO) {
        //1.查询share是否存在，不存在或者当前的audit_status
        Share share = this.shareMapper.selectByPrimaryKey(id);
        if(share==null){
            throw new IllegalArgumentException("参数非法！该分享内容不存在！");
        }
        if(!Objects.equals("NOT_YET",share.getAuditStatus())){
            throw new IllegalArgumentException("参数非法！该分享已审核通过或不通过！");
        }



        if (AuditStatusEnum.PASS.equals(auditDTO.getAuditStatusEnum())) {
            //发送半消息
            String trandsactionId=UUID.randomUUID().toString();

            this.source.output().send(
                    MessageBuilder.withPayload(
                            UserAddBonusMsgDTO.builder()
                                    .userId(share.getUserId())
                                    .bonus(50)
                                    .build()
                    )
                            //header 妙用
                            .setHeader(RocketMQHeaders.TRANSACTION_ID,trandsactionId)
                            .setHeader("share_id",id)
                            .setHeader("dto", JSON.toJSONString(auditDTO))
                            .build()
            );

            //=========================================================================
//            this.rocketMQTemplate.sendMessageInTransaction(
//                    "tx-add-bonus-group",
//                    "add-bonus",
//                    MessageBuilder.withPayload(
//                            UserAddBonusMsgDTO.builder()
//                                    .userId(share.getUserId())
//                                    .bonus(50)
//                                    .build()
//                    )
//                    //header 妙用
//                    .setHeader(RocketMQHeaders.TRANSACTION_ID,trandsactionId)
//                    .setHeader("share_id",id)
//                    .build(),
//                    //arg有大用处
//                    auditDTO
//                    );
        }else {
            this.auditByIdInDB(id,auditDTO);
        }
//        auditByIdInDB(id,auditDTO);

//        //3. 如果通过，那么发布人添加积分
//        rocketMQTemplate.convertAndSend("add-bonus", UserAddBonusMsgDTO
//                .builder()
//                .userId(share.getUserId())
//                .bonus(50)
//                .build());
        //异步执行
        //userCenterFeignClient.addBonus(id,500);
        return share;
    }


    public void auditByIdInDB(Integer id,ShareAuditDTO auditDTO) {
        //2. 审核资源，将状态设值为 通过/不通过
        Share share = Share.builder()
                .id(id)
                .auditStatus(auditDTO.getAuditStatusEnum().toString())
                .reason(auditDTO.getReason())
                .build();
//        share.setAuditStatus(auditDTO.getAuditStatusEnum().toString());
        this.shareMapper.updateByPrimaryKeySelective(share);
        //4.把share写到缓存
    }

    @Transactional(rollbackFor = Exception.class)
    public void auditByIdWithRocketMqLog(Integer id, ShareAuditDTO auditDTO, String transactionId){
        this.auditByIdInDB(id,auditDTO);

        this.rocketmqTransactionLogMapper.insertSelective(
                RocketmqTransactionLog.builder()
                .transactionId(transactionId)
                .log("审核分享。。。。")
                .build()
        );
    }

    public PageInfo<Share> q(String title, Integer pageNo, Integer pageSize, Integer userId) {
        PageHelper.startPage(pageNo, pageSize);
        List<Share> shares = this.shareMapper.selectByParam(title);
        List<Share> sharesDeal;
        // 1. 如果用户未登录，那么downloadUrl全部设为null
        if (userId == null) {
            sharesDeal = shares.stream()
                    .peek(share -> {
                        share.setDownloadUrl(null);
                    })
                    .collect(Collectors.toList());
        }
        // 2. 如果用户登录了，那么查询一下mid_user_share，如果没有数据，那么这条share的downloadUrl也设为null
        else {
            sharesDeal = shares.stream()
                    .peek(share -> {
                        MidUserShare midUserShare = this.midUserShareMapper.selectOne(
                                MidUserShare.builder()
                                        .userId(userId)
                                        .shareId(share.getId())
                                        .build()
                        );
                        if (midUserShare == null) {
                            share.setDownloadUrl(null);
                        }
                    })
                    .collect(Collectors.toList());
        }
        return new PageInfo<>(sharesDeal);
    }


    public Share exchangeById(Integer id, HttpServletRequest request) {
        Object userId = request.getAttribute("id");
        Integer integerUserId = (Integer) userId;

        // 1. 根据id查询share，校验是否存在
        Share share = this.shareMapper.selectByPrimaryKey(id);
        if (share == null) {
            throw new IllegalArgumentException("该分享不存在！");
        }
        Integer price = share.getPrice();

        // 2. 如果当前用户已经兑换过该分享，则直接返回
        MidUserShare midUserShare = this.midUserShareMapper.selectOne(
                MidUserShare.builder()
                        .shareId(id)
                        .userId(integerUserId)
                        .build()
        );
        if (midUserShare != null) {
            return share;
        }

        // 3. 根据当前登录的用户id，查询积分是否够
        UserDTO userDTO = this.userCenterFeignClient.findById(integerUserId);
        if (price > userDTO.getBonus()) {
            throw new IllegalArgumentException("用户积分不够用！");
        }

        // 4. 扣减积分 & 往mid_user_share里插入一条数据
        this.userCenterFeignClient.addBonus(
                UserAddBonseDTO.builder()
                        .userId(integerUserId)
                        .bonus(0 - price)
                        .build()
        );
        this.midUserShareMapper.insert(
                MidUserShare.builder()
                        .userId(integerUserId)
                        .shareId(id)
                        .build()
        );
        return share;
    }


}
